package com.lifeverse.service;

import com.lifeverse.entity.PerformanceMetric;
import com.lifeverse.entity.enums.MetricStatus;
import com.lifeverse.entity.enums.MetricType;
import com.lifeverse.repository.PerformanceMetricRepository;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.management.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 性能监控服务
 * 负责收集、存储和分析系统性能指标
 */
@Service
@RequiredArgsConstructor
@Slf4j
@Transactional
public class PerformanceMonitoringService {
    
    private final PerformanceMetricRepository performanceMetricRepository;
    private final MeterRegistry meterRegistry;
    
    // JMX Bean
    private final OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
    private final MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
    private final RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
    
    /**
     * 记录性能指标
     */
    public PerformanceMetric recordMetric(String metricName, MetricType metricType, 
                                        BigDecimal metricValue, String unit, 
                                        String componentName) {
        PerformanceMetric metric = PerformanceMetric.create(metricName, metricType, 
                metricValue, unit, componentName);
        
        // 设置默认阈值（可以从配置中获取）
        setDefaultThresholds(metric);
        
        return performanceMetricRepository.save(metric);
    }
    
    /**
     * 异步记录性能指标
     */
    @Async
    public CompletableFuture<PerformanceMetric> recordMetricAsync(String metricName, MetricType metricType,
                                                                BigDecimal metricValue, String unit,
                                                                String componentName) {
        try {
            PerformanceMetric metric = recordMetric(metricName, metricType, metricValue, unit, componentName);
            return CompletableFuture.completedFuture(metric);
        } catch (Exception e) {
            log.error("异步记录性能指标失败: metricName={}, metricType={}", metricName, metricType, e);
            return CompletableFuture.failedFuture(e);
        }
    }
    
    /**
     * 定时收集系统性能指标
     */
    @Scheduled(fixedRate = 30000) // 每30秒执行一次
    public void collectSystemMetrics() {
        try {
            collectCpuMetrics();
            collectMemoryMetrics();
            collectJvmMetrics();
        } catch (Exception e) {
            log.error("收集系统性能指标失败", e);
        }
    }
    
    /**
     * 收集CPU指标
     */
    private void collectCpuMetrics() {
        try {
            double cpuUsage = osBean.getProcessCpuLoad() * 100;
            if (cpuUsage >= 0) { // -1表示不可用
                recordMetric("cpu_usage", MetricType.CPU_USAGE, 
                           BigDecimal.valueOf(cpuUsage).setScale(2, RoundingMode.HALF_UP), 
                           "%", "system");
            }
            
            double systemCpuUsage = osBean.getSystemCpuLoad() * 100;
            if (systemCpuUsage >= 0) {
                recordMetric("system_cpu_usage", MetricType.CPU_USAGE,
                           BigDecimal.valueOf(systemCpuUsage).setScale(2, RoundingMode.HALF_UP),
                           "%", "system");
            }
            
            double loadAverage = osBean.getSystemLoadAverage();
            if (loadAverage >= 0) {
                recordMetric("load_average", MetricType.LOAD_AVERAGE,
                           BigDecimal.valueOf(loadAverage).setScale(2, RoundingMode.HALF_UP),
                           "count", "system");
            }
        } catch (Exception e) {
            log.error("收集CPU指标失败", e);
        }
    }
    
    /**
     * 收集内存指标
     */
    private void collectMemoryMetrics() {
        try {
            Runtime runtime = Runtime.getRuntime();
            long totalMemory = runtime.totalMemory();
            long freeMemory = runtime.freeMemory();
            long usedMemory = totalMemory - freeMemory;
            long maxMemory = runtime.maxMemory();
            
            double memoryUsage = (double) usedMemory / maxMemory * 100;
            recordMetric("memory_usage", MetricType.MEMORY_USAGE,
                       BigDecimal.valueOf(memoryUsage).setScale(2, RoundingMode.HALF_UP),
                       "%", "jvm");
            
            recordMetric("memory_used", MetricType.MEMORY_USAGE,
                       BigDecimal.valueOf(usedMemory / 1024.0 / 1024.0).setScale(2, RoundingMode.HALF_UP),
                       "MB", "jvm");
            
            recordMetric("memory_total", MetricType.MEMORY_USAGE,
                       BigDecimal.valueOf(totalMemory / 1024.0 / 1024.0).setScale(2, RoundingMode.HALF_UP),
                       "MB", "jvm");
        } catch (Exception e) {
            log.error("收集内存指标失败", e);
        }
    }
    
    /**
     * 收集JVM指标
     */
    private void collectJvmMetrics() {
        try {
            // 堆内存使用情况
            long heapUsed = memoryBean.getHeapMemoryUsage().getUsed();
            long heapMax = memoryBean.getHeapMemoryUsage().getMax();
            if (heapMax > 0) {
                double heapUsage = (double) heapUsed / heapMax * 100;
                recordMetric("jvm_heap_usage", MetricType.JVM_HEAP_USAGE,
                           BigDecimal.valueOf(heapUsage).setScale(2, RoundingMode.HALF_UP),
                           "%", "jvm");
            }
            
            // 非堆内存使用情况
            long nonHeapUsed = memoryBean.getNonHeapMemoryUsage().getUsed();
            long nonHeapMax = memoryBean.getNonHeapMemoryUsage().getMax();
            if (nonHeapMax > 0) {
                double nonHeapUsage = (double) nonHeapUsed / nonHeapMax * 100;
                recordMetric("jvm_non_heap_usage", MetricType.JVM_NON_HEAP_USAGE,
                           BigDecimal.valueOf(nonHeapUsage).setScale(2, RoundingMode.HALF_UP),
                           "%", "jvm");
            }
            
            // 线程数
            int threadCount = ManagementFactory.getThreadMXBean().getThreadCount();
            recordMetric("jvm_thread_count", MetricType.JVM_THREAD_COUNT,
                       BigDecimal.valueOf(threadCount), "count", "jvm");
            
            // 类加载数
            long loadedClassCount = ManagementFactory.getClassLoadingMXBean().getLoadedClassCount();
            recordMetric("jvm_loaded_class_count", MetricType.JVM_CLASS_COUNT,
                       BigDecimal.valueOf(loadedClassCount), "count", "jvm");
            
            // JVM运行时间
            long uptime = runtimeBean.getUptime();
            recordMetric("jvm_uptime", MetricType.CUSTOM,
                       BigDecimal.valueOf(uptime), "ms", "jvm");
            
            // GC指标
            collectGcMetrics();
            
            // 线程池指标
            collectThreadPoolMetrics();
            
        } catch (Exception e) {
            log.error("收集JVM指标失败", e);
        }
    }
    
    /**
     * 收集GC指标
     */
    private void collectGcMetrics() {
        try {
            List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
            
            for (GarbageCollectorMXBean gcBean : gcBeans) {
                String gcName = gcBean.getName().replaceAll("\\s+", "_").toLowerCase();
                
                // GC次数
                long collectionCount = gcBean.getCollectionCount();
                if (collectionCount >= 0) {
                    recordMetric("gc_collection_count_" + gcName, MetricType.CUSTOM,
                               BigDecimal.valueOf(collectionCount), "count", "jvm");
                }
                
                // GC时间
                long collectionTime = gcBean.getCollectionTime();
                if (collectionTime >= 0) {
                    recordMetric("gc_collection_time_" + gcName, MetricType.CUSTOM,
                               BigDecimal.valueOf(collectionTime), "ms", "jvm");
                }
                
                // 记录到Micrometer
                meterRegistry.counter("jvm.gc.collections", "gc", gcName)
                        .increment(collectionCount);
                meterRegistry.timer("jvm.gc.time", "gc", gcName)
                        .record(collectionTime, java.util.concurrent.TimeUnit.MILLISECONDS);
            }
            
        } catch (Exception e) {
            log.error("收集GC指标失败", e);
        }
    }
    
    /**
     * 收集线程池指标
     */
    private void collectThreadPoolMetrics() {
        try {
            ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
            
            // 线程状态统计
            long[] threadIds = threadBean.getAllThreadIds();
            ThreadInfo[] threadInfos = threadBean.getThreadInfo(threadIds);
            
            Map<Thread.State, Integer> threadStateCount = new HashMap<>();
            for (ThreadInfo threadInfo : threadInfos) {
                if (threadInfo != null) {
                    Thread.State state = threadInfo.getThreadState();
                    threadStateCount.merge(state, 1, Integer::sum);
                }
            }
            
            // 记录各种线程状态的数量
            for (Map.Entry<Thread.State, Integer> entry : threadStateCount.entrySet()) {
                String stateName = entry.getKey().name().toLowerCase();
                recordMetric("thread_state_" + stateName, MetricType.CUSTOM,
                           BigDecimal.valueOf(entry.getValue()), "count", "jvm");
                
                meterRegistry.gauge("jvm.threads.states", "state", stateName, entry.getValue());
            }
            
            // 死锁检测
            long[] deadlockedThreads = threadBean.findDeadlockedThreads();
            if (deadlockedThreads != null && deadlockedThreads.length > 0) {
                recordMetric("thread_deadlock_count", MetricType.CUSTOM,
                           BigDecimal.valueOf(deadlockedThreads.length), "count", "jvm");
                
                meterRegistry.counter("jvm.threads.deadlocks")
                        .increment(deadlockedThreads.length);
                
                log.warn("检测到线程死锁: {} 个线程", deadlockedThreads.length);
            }
            
        } catch (Exception e) {
            log.error("收集线程池指标失败", e);
        }
    }
    
    /**
     * 设置默认阈值
     */
    private void setDefaultThresholds(PerformanceMetric metric) {
        switch (metric.getMetricType()) {
            case CPU_USAGE:
                metric.withThresholds(null, BigDecimal.valueOf(100), 
                                    BigDecimal.valueOf(70), BigDecimal.valueOf(90));
                break;
            case MEMORY_USAGE:
            case JVM_HEAP_USAGE:
            case JVM_NON_HEAP_USAGE:
                metric.withThresholds(null, BigDecimal.valueOf(100),
                                    BigDecimal.valueOf(80), BigDecimal.valueOf(95));
                break;
            case RESPONSE_TIME:
                metric.withThresholds(null, null,
                                    BigDecimal.valueOf(1000), BigDecimal.valueOf(5000));
                break;
            case ERROR_RATE:
                metric.withThresholds(null, BigDecimal.valueOf(100),
                                    BigDecimal.valueOf(5), BigDecimal.valueOf(10));
                break;
            default:
                // 其他指标使用默认阈值或不设置阈值
                break;
        }
    }
    
    /**
     * 获取最新的性能指标
     */
    @Transactional(readOnly = true)
    public Optional<PerformanceMetric> getLatestMetric(String metricName) {
        return performanceMetricRepository.findTopByMetricNameOrderByMeasuredAtDesc(metricName);
    }
    
    /**
     * 获取最新的组件性能指标
     */
    @Transactional(readOnly = true)
    public Optional<PerformanceMetric> getLatestMetric(String metricName, String componentName) {
        return performanceMetricRepository.findTopByMetricNameAndComponentNameOrderByMeasuredAtDesc(
                metricName, componentName);
    }
    
    /**
     * 获取指标历史数据
     */
    @Transactional(readOnly = true)
    public List<PerformanceMetric> getMetricHistory(String metricName, LocalDateTime startTime, LocalDateTime endTime) {
        return performanceMetricRepository.findByMetricNameAndMeasuredAtBetweenOrderByMeasuredAtAsc(
                metricName, startTime, endTime);
    }
    
    /**
     * 获取组件指标历史数据
     */
    @Transactional(readOnly = true)
    public List<PerformanceMetric> getMetricHistory(String metricName, String componentName,
                                                  LocalDateTime startTime, LocalDateTime endTime) {
        return performanceMetricRepository.findByMetricNameAndComponentNameAndMeasuredAtBetweenOrderByMeasuredAtAsc(
                metricName, componentName, startTime, endTime);
    }
    
    /**
     * 获取需要关注的指标
     */
    @Transactional(readOnly = true)
    public Page<PerformanceMetric> getMetricsNeedingAttention(Pageable pageable) {
        return performanceMetricRepository.findMetricsNeedingAttention(pageable);
    }
    
    /**
     * 获取异常指标
     */
    @Transactional(readOnly = true)
    public List<PerformanceMetric> getAnomalies(LocalDateTime startTime, LocalDateTime endTime) {
        return performanceMetricRepository.findAnomaliesInTimeRange(startTime, endTime);
    }
    
    /**
     * 获取系统健康状况概览
     */
    @Transactional(readOnly = true)
    @Cacheable(value = "systemHealth", key = "'overview'", cacheManager = "performanceCacheManager")
    public Map<String, Object> getSystemHealthOverview() {
        LocalDateTime since = LocalDateTime.now().minusHours(1); // 最近1小时
        Object[] healthData = performanceMetricRepository.getSystemHealthOverview(since);
        
        Map<String, Object> overview = new HashMap<>();
        overview.put("normalCount", healthData[0]);
        overview.put("warningCount", healthData[1]);
        overview.put("abnormalCount", healthData[2]);
        overview.put("criticalCount", healthData[3]);
        
        // 计算健康评分
        long total = ((Number) healthData[0]).longValue() + ((Number) healthData[1]).longValue() +
                    ((Number) healthData[2]).longValue() + ((Number) healthData[3]).longValue();
        
        if (total > 0) {
            long normalCount = ((Number) healthData[0]).longValue();
            double healthScore = (double) normalCount / total * 100;
            overview.put("healthScore", BigDecimal.valueOf(healthScore).setScale(2, RoundingMode.HALF_UP));
        } else {
            overview.put("healthScore", BigDecimal.ZERO);
        }
        
        overview.put("timestamp", LocalDateTime.now());
        return overview;
    }
    
    /**
     * 获取性能趋势摘要
     */
    @Transactional(readOnly = true)
    public List<Map<String, Object>> getPerformanceTrendSummary(LocalDateTime startTime, LocalDateTime endTime) {
        List<Object[]> trendData = performanceMetricRepository.getPerformanceTrendSummary(startTime, endTime);
        
        return trendData.stream().map(data -> {
            Map<String, Object> trend = new HashMap<>();
            trend.put("metricName", data[0]);
            trend.put("componentName", data[1]);
            trend.put("avgValue", data[2]);
            trend.put("maxValue", data[3]);
            trend.put("minValue", data[4]);
            trend.put("sampleCount", data[5]);
            return trend;
        }).collect(Collectors.toList());
    }
    
    /**
     * 获取指标统计信息
     */
    @Transactional(readOnly = true)
    public Map<String, Object> getMetricStatistics(String metricName, LocalDateTime startTime, LocalDateTime endTime) {
        Map<String, Object> statistics = new HashMap<>();
        
        Optional<BigDecimal> avgValue = performanceMetricRepository.getAverageMetricValue(metricName, startTime, endTime);
        Optional<BigDecimal> maxValue = performanceMetricRepository.getMaxMetricValue(metricName, startTime, endTime);
        Optional<BigDecimal> minValue = performanceMetricRepository.getMinMetricValue(metricName, startTime, endTime);
        
        statistics.put("metricName", metricName);
        statistics.put("startTime", startTime);
        statistics.put("endTime", endTime);
        statistics.put("avgValue", avgValue.orElse(BigDecimal.ZERO));
        statistics.put("maxValue", maxValue.orElse(BigDecimal.ZERO));
        statistics.put("minValue", minValue.orElse(BigDecimal.ZERO));
        
        return statistics;
    }
    
    /**
     * 检测性能异常
     */
    @Scheduled(fixedRate = 60000) // 每分钟检测一次
    public void detectPerformanceAnomalies() {
        try {
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime oneHourAgo = now.minusHours(1);
            
            // 获取最近一小时的指标
            List<PerformanceMetric> recentMetrics = performanceMetricRepository
                    .findByMeasuredAtBetween(oneHourAgo, now, Pageable.unpaged())
                    .getContent();
            
            // 按指标名称分组
            Map<String, List<PerformanceMetric>> metricGroups = recentMetrics.stream()
                    .collect(Collectors.groupingBy(PerformanceMetric::getMetricName));
            
            // 对每个指标组进行异常检测
            for (Map.Entry<String, List<PerformanceMetric>> entry : metricGroups.entrySet()) {
                detectAnomaliesForMetricGroup(entry.getKey(), entry.getValue());
            }
            
        } catch (Exception e) {
            log.error("检测性能异常失败", e);
        }
    }
    
    /**
     * 对指标组进行异常检测
     */
    private void detectAnomaliesForMetricGroup(String metricName, List<PerformanceMetric> metrics) {
        if (metrics.size() < 3) {
            return; // 数据点太少，无法进行异常检测
        }
        
        // 计算统计信息
        List<BigDecimal> values = metrics.stream()
                .map(PerformanceMetric::getMetricValue)
                .collect(Collectors.toList());
        
        BigDecimal mean = values.stream()
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .divide(BigDecimal.valueOf(values.size()), 4, RoundingMode.HALF_UP);
        
        // 计算标准差
        BigDecimal variance = values.stream()
                .map(value -> value.subtract(mean).pow(2))
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .divide(BigDecimal.valueOf(values.size()), 4, RoundingMode.HALF_UP);
        
        BigDecimal stdDev = BigDecimal.valueOf(Math.sqrt(variance.doubleValue()));
        
        // 使用3-sigma规则检测异常
        BigDecimal upperBound = mean.add(stdDev.multiply(BigDecimal.valueOf(3)));
        BigDecimal lowerBound = mean.subtract(stdDev.multiply(BigDecimal.valueOf(3)));
        
        // 标记异常值
        for (PerformanceMetric metric : metrics) {
            BigDecimal value = metric.getMetricValue();
            boolean isAnomaly = value.compareTo(upperBound) > 0 || value.compareTo(lowerBound) < 0;
            
            if (isAnomaly && !Boolean.TRUE.equals(metric.getIsAnomaly())) {
                // 计算异常评分
                BigDecimal anomalyScore = calculateAnomalyScore(value, mean, stdDev);
                metric.withAnomalyInfo(true, anomalyScore);
                performanceMetricRepository.save(metric);
                
                log.warn("检测到性能异常: metricName={}, value={}, mean={}, stdDev={}, anomalyScore={}",
                        metricName, value, mean, stdDev, anomalyScore);
            }
        }
    }
    
    /**
     * 计算异常评分
     */
    private BigDecimal calculateAnomalyScore(BigDecimal value, BigDecimal mean, BigDecimal stdDev) {
        if (stdDev.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }
        
        BigDecimal zScore = value.subtract(mean).abs().divide(stdDev, 4, RoundingMode.HALF_UP);
        
        // 将z-score转换为0-1的异常评分
        BigDecimal anomalyScore = zScore.divide(BigDecimal.valueOf(5), 4, RoundingMode.HALF_UP);
        
        // 确保评分在0-1之间
        if (anomalyScore.compareTo(BigDecimal.ONE) > 0) {
            anomalyScore = BigDecimal.ONE;
        }
        
        return anomalyScore;
    }
    
    /**
     * 清理旧的性能指标数据
     */
    @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点执行
    public void cleanupOldMetrics() {
        try {
            LocalDateTime cutoffTime = LocalDateTime.now().minusDays(30); // 保留30天的数据
            performanceMetricRepository.deleteOldMetrics(cutoffTime);
            log.info("清理了 {} 之前的性能指标数据", cutoffTime);
        } catch (Exception e) {
            log.error("清理旧性能指标数据失败", e);
        }
    }
    
    /**
     * 获取所有组件名称
     */
    @Transactional(readOnly = true)
    public List<String> getAllComponentNames() {
        return performanceMetricRepository.getAllComponentNames();
    }
    
    /**
     * 获取所有指标名称
     */
    @Transactional(readOnly = true)
    public List<String> getAllMetricNames() {
        return performanceMetricRepository.getAllMetricNames();
    }
    
    /**
     * 根据指标类型获取指标
     */
    @Transactional(readOnly = true)
    public Page<PerformanceMetric> getMetricsByType(MetricType metricType, Pageable pageable) {
        return performanceMetricRepository.findByMetricType(metricType, pageable);
    }
    
    /**
     * 根据状态获取指标
     */
    @Transactional(readOnly = true)
    public Page<PerformanceMetric> getMetricsByStatus(MetricStatus status, Pageable pageable) {
        return performanceMetricRepository.findByStatus(status, pageable);
    }
}